import 'package:json_annotation/json_annotation.dart';

part 'song.g.dart';

/// 将int或String转换为String的转换器
class StringConverter implements JsonConverter<String, dynamic> {
  const StringConverter();

  @override
  String fromJson(dynamic json) {
    if (json == null) return '';
    return json.toString();
  }

  @override
  dynamic toJson(String object) => object;
}

/// 将int或String转换为可空String的转换器
class NullableStringConverter implements JsonConverter<String?, dynamic> {
  const NullableStringConverter();

  @override
  String? fromJson(dynamic json) {
    if (json == null) return null;
    return json.toString();
  }

  @override
  dynamic toJson(String? object) => object;
}

@JsonSerializable()
class Song {
  @NullableStringConverter()
  final String? id;
  final String name;
  final List<String> artist;
  final String album;
  @JsonKey(name: 'pic_id')
  @StringConverter()
  final String picId;
  @JsonKey(name: 'url_id')
  @StringConverter()
  final String urlId;
  @JsonKey(name: 'lyric_id')
  @StringConverter()
  final String lyricId;
  final String source;

  // 运行时属性（不序列化）
  @JsonKey(includeFromJson: false, includeToJson: false)
  String? audioUrl;
  
  @JsonKey(includeFromJson: false, includeToJson: false)
  String? albumImageUrl;
  
  @JsonKey(includeFromJson: false, includeToJson: false)
  String? lyric;
  
  @JsonKey(includeFromJson: false, includeToJson: false)
  String? tlyric;

  Song({
    this.id,
    required this.name,
    required this.artist,
    required this.album,
    required this.picId,
    required this.urlId,
    required this.lyricId,
    required this.source,
    this.audioUrl,
    this.albumImageUrl,
    this.lyric,
    this.tlyric,
  });

  factory Song.fromJson(Map<String, dynamic> json) => _$SongFromJson(json);
  Map<String, dynamic> toJson() => _$SongToJson(this);

  String get artistsString => artist.join(', ');
  
  /// 获取有效的ID，如果id为null则使用urlId
  String get effectiveId => id ?? urlId;

  Song copyWith({
    String? id,
    String? name,
    List<String>? artist,
    String? album,
    String? picId,
    String? urlId,
    String? lyricId,
    String? source,
    String? audioUrl,
    String? albumImageUrl,
    String? lyric,
    String? tlyric,
  }) {
    return Song(
      id: id ?? this.id,
      name: name ?? this.name,
      artist: artist ?? this.artist,
      album: album ?? this.album,
      picId: picId ?? this.picId,
      urlId: urlId ?? this.urlId,
      lyricId: lyricId ?? this.lyricId,
      source: source ?? this.source,
      audioUrl: audioUrl ?? this.audioUrl,
      albumImageUrl: albumImageUrl ?? this.albumImageUrl,
      lyric: lyric ?? this.lyric,
      tlyric: tlyric ?? this.tlyric,
    );
  }

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;
    return other is Song && other.effectiveId == effectiveId && other.source == source;
  }

  @override
  int get hashCode => effectiveId.hashCode ^ source.hashCode;
}